package view.graph;

import datacontainer.ImmuTable;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics2D;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;


/**
 * This class serves to generate a pie graph using a general algorithm
 * of any appropriate data type. The graph's foundations are first initialized,
 * making sure the Pie is kept circular regardless of the user's toying choice
 * of
 * dimensions. Using allocations of the data's corresponding percentages,
 * the fillArc method efficiently creates the Pie's subdivisions by drawing
 * and painting slices of the circle. A Handy Key on the left side is also
 * generated.
 * Additionally, the Chart's color scheme is randomized for each display load!
 * 
 * @author Oren Bukspan
 * @author Kannan Raju
 */
public class PieChart extends AbstractVisualization {

    private static final int X_VAR = 0;
    private static final int Y_VAR = 1;
    private static final int KEY_COLUMN_SEPARATOR_CONSTANT = 4;
    private static final int NUMBER_OF_ENTRIES_IN_KEYCOLUMN = 25;
    private static final int KEY_BOX_BOTTOM_OFFSET = 2;
    private static final double X_PROPORTION = 0.20;
    private static final double Y_PROPORTION = 0.20;
    private static final double ADDITIONAL_CHART_DISPLACEMENT = .1;
    private static final double TITLE_PROPORTION = .05;
    private static final int DEGREES_IN_CIRCLE = 360;
    private static final int ONE_HUNDRED_PERCENT = 100;
    private static final int TITLE_SCREEN_WIDTH_DIVISOR = 4;
    private static final float VISUALIZATION_TITLE_FONT_SIZE = 19.0f;

    private List<String> myHeaders;
    private List<Double> myAngles;
    private List<String> myNames;
    private List<Color> myColors;


    @Override
    public void inputData (ImmuTable data) {
        myColors = new ArrayList<Color>();
        myAngles = new ArrayList<Double>();
        List<String> strAL = data.getColumn(Y_VAR);
        for (String str : strAL) {
            double d = Double.parseDouble(str);
            myAngles.add(d / ONE_HUNDRED_PERCENT * DEGREES_IN_CIRCLE);
        }
        myNames = data.getColumn(X_VAR);
        myHeaders = data.getHeaders();
    }

    @Override
    public void paintComponent (Graphics2D graphics, Dimension dim) {
        int windowWidth = dim.width;
        int windowHeight = dim.height;

        int smallerDimension = windowWidth < windowHeight ? windowWidth : windowHeight;
        int xVal = (int) ((X_PROPORTION * smallerDimension) +
                ADDITIONAL_CHART_DISPLACEMENT * windowWidth);
        int yVal = (int) ((Y_PROPORTION * smallerDimension));
        int chartWidth = (int) (smallerDimension * (1 - 2 * X_PROPORTION));
        int chartHeight = (int) (smallerDimension * (1 - 2 * Y_PROPORTION));
        int startAngle = 0;

        setUpVisualisationBackground(graphics, windowWidth, windowHeight);
        drawPieChart(graphics, xVal, yVal, chartWidth, chartHeight, startAngle);
        drawKey(graphics, windowHeight);
        setTitle(graphics, windowWidth, windowHeight);
    }

    @Override
    public void setUpVisualisationBackground (Graphics2D graphics,
                                              int windowWidth, int windowHeight) {
        graphics.setColor(Color.BLACK);
        graphics.fillRect(0, 0, windowWidth, windowHeight);
    }

    private void setTitle (Graphics2D graphics, int windowWidth, int windowHeight) {
        graphics.setColor(Color.WHITE);
        int xVal;
        int yVal;
        yVal = (int) (TITLE_PROPORTION * windowHeight);
        xVal = windowWidth / TITLE_SCREEN_WIDTH_DIVISOR;
        Font originalFont = graphics.getFont();
        Font titleFont = graphics.getFont();
        titleFont = titleFont.deriveFont(VISUALIZATION_TITLE_FONT_SIZE);
        graphics.setFont(titleFont);
        graphics.drawString("Percentage of " + myHeaders.get(Y_VAR) + " " + "by " +
                                    myHeaders.get(X_VAR), xVal, yVal);
        graphics.setFont(originalFont);
    }

    private void drawPieChart (Graphics2D graphics, int xVal, int yVal, int chartWidth,
                               int chartHeight, int startAngle) {
        int arcAngle = 0;
        int startingAngle = startAngle;
        Random generator = new Random();
        for (int i = 0; i < myAngles.size(); i++) {
            myColors.add(new Color(generator.nextInt()));
        }

        for (int i = 0; i < myAngles.size(); i++) {
            arcAngle = (int) Math.round(myAngles.get(i).doubleValue());
            if (i == myAngles.size() - 1) {
                arcAngle = DEGREES_IN_CIRCLE - startingAngle;
            }
            graphics.setColor(myColors.get(i));
            graphics.fillArc(xVal, yVal, chartWidth, chartHeight, startingAngle, arcAngle);
            startingAngle += arcAngle;
        }
    }

    private void drawKey (Graphics2D graphics, int windowHeight) {
        int fontSize = graphics.getFont().getSize();
        int yKeyTitleLocation = (int) (fontSize +
                (windowHeight * TITLE_PROPORTION));
        int xValOfKeyEntryLocation = 0;
        String keyTitle = drawKeyTitle(graphics, yKeyTitleLocation, xValOfKeyEntryLocation);
        int maxWidthOfKeyEntries = determineMaxWidthOfKeyEntries(graphics);
        int yKeyEntryStartingValue = fontSize + yKeyTitleLocation;
        int yValOfKeyEntryLocation = yKeyEntryStartingValue;
        int countOfKeyColumns = 1;
        int countOfKeyEntries = 0;
        for (int i = 0; i < myNames.size(); i++) {
            if (countOfKeyEntries == NUMBER_OF_ENTRIES_IN_KEYCOLUMN) {
                xValOfKeyEntryLocation += maxWidthOfKeyEntries;
                yValOfKeyEntryLocation = yKeyEntryStartingValue;
                countOfKeyEntries = 0;
                countOfKeyColumns += 1;
            }
            graphics.setColor(myColors.get(i));
            graphics.drawString(myNames.get(i), xValOfKeyEntryLocation, yValOfKeyEntryLocation);
            yValOfKeyEntryLocation += fontSize;
            countOfKeyEntries += 1;
        }
        drawKeyBox(graphics, fontSize, yKeyTitleLocation, keyTitle, maxWidthOfKeyEntries,
                   countOfKeyColumns, countOfKeyEntries);
    }

    private String drawKeyTitle (Graphics2D graphics, int yKeyTitleLocation,
                                 int xValOfKeyEntryLocation) {
        graphics.setColor(Color.WHITE);
        String keyTitle = "Key: " + myHeaders.get(X_VAR);
        graphics.drawString(keyTitle,
                            xValOfKeyEntryLocation, yKeyTitleLocation);
        return keyTitle;
    }

    private void drawKeyBox (Graphics2D graphics, int fontSize, int yKeyTitleLocation,
                             String keyTitle, int maxWidthOfKeyEntries, int countOfKeyColumns,
                             int countOfKeyEntries) {
        int boxWidth = maxWidthOfKeyEntries * countOfKeyColumns;
        if (boxWidth < graphics.getFontMetrics().stringWidth(keyTitle)) {
            boxWidth = graphics.getFontMetrics().stringWidth(keyTitle);
        }
        int boxHeight = (NUMBER_OF_ENTRIES_IN_KEYCOLUMN + KEY_BOX_BOTTOM_OFFSET) *
                fontSize;
        if (countOfKeyColumns == 1) {
            boxHeight = (countOfKeyEntries + KEY_BOX_BOTTOM_OFFSET) * fontSize;
        }
        graphics.setColor(Color.WHITE);
        graphics.drawRect(0, yKeyTitleLocation - fontSize, boxWidth, 
                          boxHeight);
    }

    private int determineMaxWidthOfKeyEntries (Graphics2D graphics) {
        int maxWidthOfKeyEntry = 0;
        for (int i = 0; i < myNames.size(); i++) {
            if (graphics.getFontMetrics().stringWidth(myNames.get(i)) > maxWidthOfKeyEntry) {
                maxWidthOfKeyEntry = graphics.getFontMetrics().stringWidth(myNames.get(i));
            }
        }
        maxWidthOfKeyEntry += KEY_COLUMN_SEPARATOR_CONSTANT;
        return maxWidthOfKeyEntry;
    }
}
